/*
   Copyright (c) 2008-2009 LW, Inc. <http://www.lw.com>
   This file is part of LWFS.

   LWFS is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published
   by the Free Software Foundation; either version 3 of the License,
   or (at your option) any later version.

   LWFS is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program.  If not, see
   <http://www.gnu.org/licenses/>.
*/

#ifndef _CONFIG_H
#define _CONFIG_H
#include "config.h"
#endif

#ifndef _COMBINE_H
#define _COMBINE_H


struct combine_local {
	int                      op_ret;
	int                      op_errno;
	int                      call_cnt;
        int                      file_count;
        int                      dir_count;
	ino_t                    st_ino;
        ino_t                    st_dev;
	loc_t                    loc;
        /* Use stbuf as the postbuf, when we require both
         * pre and post attrs */
	struct stat              stbuf;
	struct statvfs		 statvfs;
	fd_t                    *fd;
	inode_t                 *inode;
	size_t                   size;
	xlator_t                *cmbn_cached;
	dict_t                  *xattr_req;
};

typedef struct combine_local combine_local_t;

struct combine_conf {
	gf_lock_t      subvolume_lock;
        int            subvolume_cnt;
        xlator_t     **subvolumes;
	char          *subvolume_status;
        char           disk_unit;
        int32_t        refresh_interval;
	struct timeval last_stat_fetch;
        gf_lock_t      layout_lock;
        void          *private;     /* Can be used by wrapper xlators over combine */
};
typedef struct _combine_inode_ctx {
	char		local;
	uint64_t	gen;
        uint64_t	ino;
	xlator_t 	*position;
} combine_inode_ctx_t;

typedef struct _combine_fd_ctx {
        char              local;
        uint64_t          ino;
        uint64_t          gen;
        char              is_dir;
        char              released;
        int32_t           flags;
        int32_t           wbflags;
	xlator_t 	*position;
} combine_fd_ctx_t;

typedef struct combine_conf combine_conf_t;

#define COMBINE_STACK_UNWIND(fop, frame, params ...) do {       \
		combine_local_t *__local = NULL;                \
                xlator_t *__xl = NULL;                          \
                __xl = frame->this;                             \
		__local = frame->local;                         \
		frame->local = NULL;                            \
		STACK_UNWIND_STRICT (fop, frame, params);       \
		combine_local_wipe (__xl, __local);             \
	} while (0)

#define is_last_call(cnt) (cnt == 0)
#define check_is_dir(i,s,x) (S_ISDIR(s->st_mode))

#define set_if_greater(a, b) do {		\
		if ((a) < (b))			\
			(a) = (b);		\
	} while (0)


int combine_init_subvolumes (xlator_t *this, combine_conf_t *conf);
int combine_frame_return (call_frame_t *frame);

void combine_local_wipe (xlator_t *this, combine_local_t *local);
combine_local_t *combine_local_init (call_frame_t *frame);
int combine_stat_merge (xlator_t *this, struct stat *to, struct stat *from, xlator_t *subvol);
int32_t combine_fd_set_ctx (fd_t *file, xlator_t *this, loc_t *loc, combine_fd_ctx_t *ctx);
xlator_t *combine_vol_by_loc (xlator_t *this, loc_t *loc);
int combine_itransform (xlator_t *this, xlator_t *subvol, uint64_t x, uint64_t *y_p);
int combine_deitransform (xlator_t *this, uint64_t y, xlator_t **subvol_p,uint64_t *x_p);
xlator_t *combine_subvol_next (xlator_t *this, xlator_t *prev);
int combine_is_local_loc (xlator_t *this, loc_t *loc);
#endif
